package com.tbit.uqbike.util;

import java.util.Date;
import java.util.LinkedList;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by MyWin on 2017/5/9.
 */
public class BatHandle implements Runnable {
    /**
     * 公共使用的线程池
     */
    public static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    /**
     * 超时插入时间
     */
    private int _timeoutSec;
    /**
     * 批量插入的阈值
     */
    private int _batInsertN;
    /**
     * 循环检测超时时间
     */
    private int _checkTimeoutSec;
    /**
     * 最后一次插入时间
     */
    private Date _lastHandleDt;
    /**
     *
     */
    private LinkedList<IBatHandle> _list;
    /**
     * 同步对象
     */
    private ReentrantLock _lock;
    /**
     * 运行标志
     */
    private boolean _acitve;
    private boolean _bhandle;
    /**
     *
     */
    private Semaphore _semaphore;

    public BatHandle(int timeoutSec, int batInsertN, int checkTimeoutSec) {
        this._timeoutSec = timeoutSec;
        this._batInsertN = batInsertN;
        this._checkTimeoutSec = checkTimeoutSec;
        this._lastHandleDt = new Date();
        this._list = new LinkedList<>();
        this._lock = new ReentrantLock();
        this._acitve = false;
        this._bhandle = false;
        this._semaphore = new Semaphore(1);
    }

    public BatHandle() {
        this._timeoutSec = 20;
        this._batInsertN = 2048;
        this._checkTimeoutSec = 10;
        this._lastHandleDt = new Date();
        this._list = new LinkedList<>();
        this._lock = new ReentrantLock();
        this._acitve = false;
        this._bhandle = false;
        this._semaphore = new Semaphore(1);
    }

    public void addHandleItem(IBatHandle item) {
        LinkedList<IBatHandle> insertList = null;
        Date currDt = new Date();
        try {
            _lock.lock();
            _list.add(item);
            // 数量够的时候插入
            if (_list.size() > _batInsertN) {
                insertList = _list;
                _list = new LinkedList<IBatHandle>();
                _lastHandleDt = currDt;
            } else if (DateUtil.GetTimeSpanSec(_lastHandleDt, currDt) > _timeoutSec) {
                insertList = _list;
                _list = new LinkedList<IBatHandle>();
                _lastHandleDt = currDt;
            }
        } finally {
            _lock.unlock();
        }
        if (null != insertList) {
            item.insertData(insertList);
        }
    }

    @Override
    public void run() {
        _acitve = true;
        try {
            _semaphore.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (_acitve) {
            boolean flag = false;
            try {
                flag = _semaphore.tryAcquire(_checkTimeoutSec, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Date currDt = new Date();
            if (!flag) {
                if (DateUtil.GetTimeSpanSec(_lastHandleDt, currDt) > _timeoutSec) {
                    LinkedList<IBatHandle> insertList = getAllMsg();
                    if (null != insertList && insertList.size() > 0) {
                        insertList.getFirst().insertData(insertList);
                    }
                }
            } else {
                break;
            }
        }
        if (_bhandle) {
            LinkedList<IBatHandle> insertList = getAllMsg();
            if (null != insertList && insertList.size() > 0) {
                insertList.getFirst().insertData(insertList);
            }
        }
    }

    /**
     * 获取所有数据
     *
     * @return
     */
    private LinkedList<IBatHandle> getAllMsg() {
        LinkedList<IBatHandle> insertList = null;
        Date currDt = new Date();
        try {
            _lock.lock();
            insertList = _list;
            _list = new LinkedList<IBatHandle>();
            _lastHandleDt = currDt;
        } finally {
            _lock.unlock();
        }
        return insertList;
    }

    /**
     * 停止服务
     *
     * @param bhandle 标识是否需要处理完缓存的数据
     */
    public void stopService(boolean bhandle) {
        _acitve = false;
        _bhandle = bhandle;
        _semaphore.release();
    }
}
